using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class FieldOfView : MonoBehaviour
{

    public float viewRadius; // 视野半径
    [Range(0, 360)]
    public float viewAngle; // 视野角度（0-360度）

    [Header("层级遮罩")]
    public LayerMask targetMask; // 目标层级
    public LayerMask obstacleMask; // 障碍物层级

    [HideInInspector]
    public List<Transform> visibleTargets = new List<Transform>(); // 可见目标列表

    [Header("视野网格参数")]
    public float meshResolution;      // 网格分辨率(每度有多少条射线)
    public int edgeResolveIterations; // 边缘解析迭代次数(用于平滑边缘)
    public float edgeDstThreshold;    // 边缘距离阈值(决定何时需要细分边缘)
    public float maskCutawayDst = 0.15f; //阴影摆动幅度

    [Header("网格引用")]
    public MeshFilter viewMeshFilter; // 用于显示视野的网格过滤器
    Mesh viewMesh;                    // 视野网格实例

    void Start()
    {
        // 初始化视野网格
        viewMesh = new Mesh();
        viewMesh.name = "View Mesh";
        viewMeshFilter.mesh = viewMesh;

        // 开始协程，每隔一定时间查找目标
        StartCoroutine(nameof(FindTargetsWithDelay), .2f);
    }

    // 延迟查找目标的协程
    IEnumerator FindTargetsWithDelay(float delay)
    {
        while (true)
        {
            yield return new WaitForSeconds(delay); // 等待指定延迟
            FindVisibleTargets(); // 查找可见目标
        }
    }

    // 查找可见目标的方法
    void FindVisibleTargets()
    {
        visibleTargets.Clear(); // 清空可见目标列表
                                // 获取视野半径内的所有目标碰撞体
        Collider[] targetsInViewRadius = Physics.OverlapSphere(transform.position, viewRadius, targetMask);

        for (int i = 0; i < targetsInViewRadius.Length; i++)
        {
            Transform target = targetsInViewRadius[i].transform; // 获取目标变换组件
            Vector3 dirToTarget = (target.position - transform.position).normalized; // 计算到目标的归一化方向
                                                                                     // 检查目标是否在视野角度内
            if (Vector3.Angle(transform.forward, dirToTarget) < viewAngle / 2)
            {
                float dstToTarget = Vector3.Distance(transform.position, target.position); // 计算到目标的距离

                // 检查目标之间是否有障碍物遮挡
                if (!Physics.Raycast(transform.position, dirToTarget, dstToTarget, obstacleMask))
                {
                    visibleTargets.Add(target); // 如果没有遮挡，添加到可见列表
                }
            }
        }
    }

    void LateUpdate()
    {
        DrawFieldOfView(); // 在LateUpdate中绘制视野，确保在所有更新完成后执行
    }

    // 绘制视野范围
    void DrawFieldOfView()
    {
        int stepCount = Mathf.RoundToInt(viewAngle * meshResolution); // 计算需要多少步(射线)
        float stepAngleSize = viewAngle / stepCount; // 每一步的角度大小
        List<Vector3> viewPoints = new List<Vector3>(); // 存储所有视野边界点

        ViewCastInfo oldViewCast = new ViewCastInfo();
        for (int i = 0; i <= stepCount; i++)
        {
            // 计算当前角度(从左侧开始到右侧)
            float angle = transform.eulerAngles.y - viewAngle / 2 + stepAngleSize * i;
            ViewCastInfo newViewCast = ViewCast(angle); // 发射射线检测碰撞

            // 从第二步开始检查边缘
            if (i > 0)
            {
                bool edgeDstThresholdExceeded = Mathf.Abs(oldViewCast.dst - newViewCast.dst) > edgeDstThreshold;

                // 如果命中状态改变或距离超过阈值，需要查找边缘
                if (oldViewCast.hit != newViewCast.hit || (oldViewCast.hit && newViewCast.hit && edgeDstThresholdExceeded))
                {
                    EdgeInfo edge = FindEdge(oldViewCast, newViewCast); // 查找精确边缘
                    if (edge.pointA != Vector3.zero)
                    {
                        viewPoints.Add(edge.pointA);
                    }
                    if (edge.pointB != Vector3.zero)
                    {
                        viewPoints.Add(edge.pointB);
                    }
                }
            }

            viewPoints.Add(newViewCast.point); // 添加当前点
            oldViewCast = newViewCast; // 保存当前点供下次比较
        }

        // 创建网格
        int vertexCount = viewPoints.Count + 1; // 顶点数(所有边界点+中心点)
        Vector3[] vertices = new Vector3[vertexCount];
        int[] triangles = new int[(vertexCount - 2) * 3]; // 三角形数

        vertices[0] = Vector3.zero; // 第一个顶点是中心点(本地坐标)
        for (int i = 0; i < vertexCount - 1; i++)
        {
            // 将世界坐标转换为本地坐标
            vertices[i + 1] = transform.InverseTransformPoint(viewPoints[i])  + Vector3.forward * maskCutawayDst;

            // 构建三角形(扇形)
            if (i < vertexCount - 2)
            {
                triangles[i * 3] = 0;
                triangles[i * 3 + 1] = i + 1;
                triangles[i * 3 + 2] = i + 2;
            }
        }

        // 更新网格
        viewMesh.Clear();
        viewMesh.vertices = vertices;
        viewMesh.triangles = triangles;
        viewMesh.RecalculateNormals();
    }

    // 查找两个ViewCast之间的精确边缘
    EdgeInfo FindEdge(ViewCastInfo minViewCast, ViewCastInfo maxViewCast)
    {
        float minAngle = minViewCast.angle;
        float maxAngle = maxViewCast.angle;
        Vector3 minPoint = Vector3.zero;
        Vector3 maxPoint = Vector3.zero;

        // 使用二分法迭代查找精确边缘
        for (int i = 0; i < edgeResolveIterations; i++)
        {
            float angle = (minAngle + maxAngle) / 2;
            ViewCastInfo newViewCast = ViewCast(angle);

            bool edgeDstThresholdExceeded = Mathf.Abs(minViewCast.dst - newViewCast.dst) > edgeDstThreshold;
            if (newViewCast.hit == minViewCast.hit && !edgeDstThresholdExceeded)
            {
                minAngle = angle;
                minPoint = newViewCast.point;
            }
            else
            {
                maxAngle = angle;
                maxPoint = newViewCast.point;
            }
        }

        return new EdgeInfo(minPoint, maxPoint);
    }

    // 从指定角度发射射线检测
    ViewCastInfo ViewCast(float globalAngle)
    {
        Vector3 dir = DirFromAngle(globalAngle, true);
        RaycastHit hit;

        if (Physics.Raycast(transform.position, dir, out hit, viewRadius, obstacleMask))
        {
            // 如果命中障碍物，返回命中信息
            return new ViewCastInfo(true, hit.point, hit.distance, globalAngle);
        }
        else
        {
            // 如果没有命中，返回最大距离的点
            return new ViewCastInfo(false, transform.position + dir * viewRadius, viewRadius, globalAngle);
        }
    }

    // 根据角度获取方向向量
    public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal)
    {
        if (!angleIsGlobal)
        {
            angleInDegrees += transform.eulerAngles.y; // 如果不是全局角度，加上物体的y轴旋转
        }
        return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
    }

    // 视野投射信息结构体
    public struct ViewCastInfo
    {
        public bool hit;     // 是否命中障碍物
        public Vector3 point; // 命中点或最大距离点
        public float dst;     // 距离
        public float angle;   // 角度

        public ViewCastInfo(bool _hit, Vector3 _point, float _dst, float _angle)
        {
            hit = _hit;
            point = _point;
            dst = _dst;
            angle = _angle;
        }
    }

    // 边缘信息结构体
    public struct EdgeInfo
    {
        public Vector3 pointA; // 边缘点A
        public Vector3 pointB; // 边缘点B

        public EdgeInfo(Vector3 _pointA, Vector3 _pointB)
        {
            pointA = _pointA;
            pointB = _pointB;
        }
    }
}